#!/bin/bash -e
#   * compile instructions: put this file in
#   *         `steamapps/common/Dyson Sphere Program/CustomMod`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x powerFull.cs
#   *     ./powerFull.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

export IFS=$'\n' # to disable the annoying space.
export DOTNET=dotnet # the location of the DOTNET executable file.
[ -z "$DOTNET_CSC_DLL" ] && export DOTNET_CSC_DLL=`\ls /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll` # In manjaro, the csc.dll is located in /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll

__MODE_VERBOSE=78 # is the line number of "#define VERBOSE", may be modified
__MODE_DEBUG__=$((__MODE_VERBOSE+1))
__MODE_RELEASE=$((__MODE_DEBUG__+1))

case $1 in
    V)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    v)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    VERBOSE) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    verbose) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    D)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    d)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    DEBUG)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    debug)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    *)       _MODE__SELECT_=$__MODE_RELEASE     ;;
esac

export GAME_BASE_DIR="common/Othercide"
export FILE_NAME="$0"
export ASSEMBLY="Assembly-CSharp"
export PLUGIN_ID="Neutron3529.Cheat"
export NAMESPACE_ID="Neutron3529.Cheat"

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_ ) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $DOTNET $DOTNET_CSC_DLL -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Core.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.IL2CPP.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/UnhollowerBaseLib.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/unhollowed/Il2Cppmscorlib.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/unhollowed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/unhollowed/UnityEngine.UI.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/unhollowed/UnityEngine.CoreModule.dll" \
  $(for i in "${GAME_BASE_DIR}/BepInEx/unhollowed/$ASSEMBLY"*.dll ; do echo -e "-r:\"$i\"\n" ; done) \
  `[ -e "${GAME_BASE_DIR}/mono/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/mono/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/mono/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/mono/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/mono/Managed/mscorlib.dll" \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize `[ x"$_MODE__SELECT_" == x"$__MODE_DEBUG__" ] && echo -debug` \
  - && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
    git add ${FILE_NAME}
    case $2 in
        R) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        r) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        RANDOM) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        random) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        U) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        u) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        UPLOAD) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        upload) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        *) git commit -am "$2" ;;
    esac
    git push
fi
exit

#define VERBOSE // the line of __MODE_VERBOSE
#define DEBUG




using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.IL2CPP;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

namespace %%NAMESPACE_ID%%
{
    [BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.0")]
    public class Cheat : BasePlugin {
//         static int xpmul=100;
//         static int xpadd=10000;
        static float statadd=0f;
        static bool juewu=true;
#if DEBUG
        public static Action<string> logger;
#else
        public static void logger(string s){}
#endif
        public override void Load() {
            var harmony=new Harmony("%%PLUGIN_ID%%");
#if DEBUG
            logger=Log.LogInfo;
#endif
            logger("叮~您的修改器已启动");
            if((statadd=Config.Bind("config", "statadd", statadd, "升级属性增加值").Value)>0){
                harmony.PatchAll(typeof(UnitCharacteristicsRepositoryIncreaseUnitMasterStats));
                logger("%%PLUGIN_ID%%-升级属性更改为增加"+statadd.ToString()+"-注入完成");
            }
            if(Config.Bind("config", "remove trait restriction", true, "解除特性解锁限制").Value){
//                 harmony.PatchAll(typeof(TraitManagerApplyUnlockedTraitsDuringLastBattle));
//                 harmony.PatchAll(typeof(TraitManagerTryValidateTrigger));
                harmony.PatchAll(typeof(TraitManagerIsTriggerConditionValid));
                logger("%%PLUGIN_ID%%-解除特性解锁限制-注入完成");
            }
            if(Config.Bind("config", "trait unlockProb", true, "处理特性解锁概率").Value){
                harmony.PatchAll(typeof(SimulationDoMissionStart));
                logger("%%PLUGIN_ID%%-处理特性解锁概率-注入完成");
                juewu=Config.Bind("config", "imba trait", true, "不平衡trait:将“觉悟”修改成永动机类身法").Value;
            } else {
                Config.Bind("config", "imba trait", false, "不平衡trait:将“觉悟”修改成永动机类身法").Value=false;
                juewu=false;
            }
//             if((xpmul=Config.Bind("config", "xp mul", xpmul, "XP倍率").Value)>1){
//                 harmony.PatchAll(typeof(XPManagerCalculateXPGainWithModifiers));
//                 logger("%%PLUGIN_ID%%-"+xpmul.ToString()+"倍XP-注入完成");
//             }

//             if((xpadd=Config.Bind("config", "xp add", xpadd, "XP 加值").Value)>0){
//                 harmony.PatchAll(typeof(XPManagerCalculateXPGainWithModifiers));
//                 //harmony.PatchAll(typeof(XPGainConstructor));//contains bug.
//                 logger("%%PLUGIN_ID%%-missioin XP 与 kill XP 同时增加"+xpadd.ToString()+"-注入完成");
//             }

//             if((xpadd=Config.Bind("config", "ap add", xpadd, "将AP初始值改为10000").Value)>0){
//                 harmony.PatchAll(typeof(XPManagerCalculateXPGainWithModifiers));
//                 //harmony.PatchAll(typeof(XPGainConstructor));//contains bug.
//                 logger("%%PLUGIN_ID%%-missioin XP 与 kill XP 同时增加"+xpadd.ToString()+"-注入完成");
//             }
            //harmony.PatchAll(typeof(BaseUnitSetAP));
        }
        [HarmonyPatch(typeof(BoH.Repository.UnitCharacteristicsRepository), "IncreaseUnitMasterStats")]
        class UnitCharacteristicsRepositoryIncreaseUnitMasterStats {
            public static bool Prefix(ref BoH.Managers.XPManager.MasterStats increaseStats) {
                logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}]", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second)
                    +" 4 dimensions triggered."
                    +" increaseStats.Adroitness="+increaseStats.Adroitness.ToString()
                    +" increaseStats.Acuity="+increaseStats.Acuity.ToString()
                    +" increaseStats.Vibrancy="+increaseStats.Vibrancy.ToString()
                    +" increaseStats.Cohesion="+increaseStats.Cohesion.ToString()
                );
                increaseStats.Adroitness=statadd;
                increaseStats.Acuity=statadd;
                increaseStats.Vibrancy=statadd;
                increaseStats.Cohesion=statadd;
//                 logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}]", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second)
//                     +" after 4 dimensions triggered."
//                     +" increaseStats.Adroitness="+increaseStats.Adroitness.ToString()
//                     +" increaseStats.Acuity="+increaseStats.Acuity.ToString()
//                     +" increaseStats.Vibrancy="+increaseStats.Vibrancy.ToString()
//                     +" increaseStats.Cohesion="+increaseStats.Cohesion.ToString()
//                 );
                return true;
            }
        }
//         [HarmonyPatch(typeof(BoH.Managers.TraitManager), "ApplyUnlockedTraitsDuringLastBattle")]
//         class TraitManagerApplyUnlockedTraitsDuringLastBattle {
//             public static bool Prefix(BoH.Managers.TraitManager __instance) {
//                 logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}] Enter ApplyUnlockedTraitsDuringLastBattle", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second));
//
//                 return true;
//             }
//         }
//         [HarmonyPatch(typeof(BoH.Managers.TraitManager), "TryValidateTrigger")]
//         class TraitManagerTryValidateTrigger {
//             public static bool Prefix(BoH.Managers.TraitManager __instance, BoH.Traits.Trait trait) {
//                 logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}] Enter TryValidateTrigger-pre ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second)+", trait="+trait.Data.NameLoc+", positive="+(!trait.Data.IsNegative)+", UnlockProbability="+trait.Data.UnlockProbability);
//                 if((!trait.Data.IsNegative) && trait.Data.UnlockProbability<100){
//                     trait.Data.UnlockProbability=100;
//                     if(trait.Data.NameLoc=="TXT_DATA_TRAIT_LEARNFROMADVERSITY_TITLE"){
//                         trait.Data.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.XP_GATHER_FACTOR,500,true));
//                         trait.Data.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.MOVEMENT_RANGE,50,true));
//                         trait.Data.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.MEMORY_EQUIP_COST_FACTOR,-100,true));
//                         trait.Data.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.CRITICAL_CHANCE,100,true));
//                         trait.Data.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.END_OF_TURN_OFFSET,-10,true));
//                         trait.Data.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.AP,850,true));
//                     }
//                     logger("觉悟-patched");
//                 }
//                 return true;
//             }
//             public static void Postfix(BoH.Managers.TraitManager __instance, BoH.Traits.Trait trait, ref bool __result) {
//                 logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}] Enter TryValidateTrigger-post", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second)+", traitdesc="+I2.Loc.LocalizedString.GetLocalizedText(trait.Data.DescriptionLoc)+", result="+__result+", modifierlen"+trait.Data.ModifiersList.Count);
//                 if(!trait.Data.IsNegative){
//                     __result=true;
//                 }
//             }
//         }
        [HarmonyPatch(typeof(BoH.Managers.TraitManager), "IsTriggerConditionValid")]
        class TraitManagerIsTriggerConditionValid {
//             public static bool Prefix(BoH.Managers.TraitManager __instance, BoH.Traits.Trait trait) {
//                 logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}] Enter IsTriggerConditionValid-pre ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second)+", trait="+trait.Data.NameLoc+", positive="+(!trait.Data.IsNegative)+", UnlockProbability="+trait.Data.UnlockProbability);
//                 if(!trait.Data.IsNegative){
//                      trait.Data.UnlockProbability=100;
//                 }
//                 return true;
//             }
            public static void Postfix(BoH.Managers.TraitManager __instance, BoH.Traits.Trait trait, ref bool __result) {
                logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}] Enter IsTriggerConditionValid-post", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second)+", traitname="+I2.Loc.LocalizedString.GetLocalizedText(trait.Data.NameLoc)+", result="+__result);
                if(!trait.Data.IsNegative){
                    __result=true;
                }
            }
        }

        [HarmonyPatch(typeof(BoH.Simulation), "DoMissionStart")]
        class SimulationDoMissionStart {
            public static void Postfix(BoH.Simulation __instance) {
                logger(string.Format("[{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}] Enter DoMissionStart-post",
                                     DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute,  DateTime.Now.Second));
                foreach(BoH.TraitScriptableObject trait in __instance.m_TraitManager.m_UnlockableTraits){
                    logger("trait NameLoc="+trait.NameLoc+" - "+I2.Loc.LocalizedString.GetLocalizedText(trait.NameLoc)+":"+I2.Loc.LocalizedString.GetLocalizedText(trait.DescriptionLoc));
                    if((!trait.IsNegative) && trait.UnlockProbability<100){
                        trait.UnlockProbability=100;
                        if(trait.NameLoc=="TXT_DATA_TRAIT_LEARNFROMADVERSITY_TITLE" && juewu){
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.XP_GATHER_FACTOR,500,true));
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.MOVEMENT_RANGE,50,true));
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.MEMORY_EQUIP_COST_FACTOR,-100,true));
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.CRITICAL_CHANCE,100,true));
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.END_OF_TURN_OFFSET,-10,true));
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.AP,850,true));
                            trait.ModifiersList.Add(new BoH.TraitScriptableObject.Modifier(BoH.Stat.AGGRO_FACTOR,10,true));
                            logger("觉悟-patched");
                        }
                    }
                }
            }
        }
//         [HarmonyPatch(typeof(BoH.Managers.XPManager), "CalculateXPGainWithModifiers")]
//         class XPManagerCalculateXPGainWithModifiers {
//             public static bool Prefix(int xpBase) {
//                 xpBase*=xpmul;
//                 return true;
//             }
//         }
//         [HarmonyPatch(typeof(BoH.GameStateManager.MissionReportHolder), "GetXPGain")]
//         class MissionReportHolderGetXPGain {
//             public static void Postfix(BoH.Managers.XPManager.XPGain __result) {
//                 logger("GetXPGain patch triggered.");
//                 if(__result._Mission_k__BackingField<xpadd)__result._Mission_k__BackingField+=xpadd;
//                 if(__result._Kill_k__BackingField<xpadd)__result._Kill_k__BackingField+=xpadd;
//             }
//         }
//         class XPGainConstructor {
//             static IEnumerable<MethodBase> TargetMethods() {
//                 foreach(ConstructorInfo i in typeof(BoH.Managers.XPManager.XPGain).GetConstructors((BindingFlags)(-1))){
//                     logger(i.ToString()+" patched.");
//                     yield return i;
//                 }
//             }
//             public static void Postfix(BoH.Managers.XPManager.XPGain __instance) {
//                 logger("XPGainConstructor patch triggered.");
//                 if(__instance._Mission_k__BackingField<xpadd)__instance._Mission_k__BackingField+=xpadd;
//                 if(__instance._Kill_k__BackingField<xpadd)__instance._Kill_k__BackingField+=xpadd;
//             }
//         }
//         [HarmonyPatch(typeof(BoH.Units.BaseUnit), "SetAP")] // debug only, useless.
//         class BaseUnitSetAP {
//             public static bool Prefix(ref float newAPValue) {
//                 if(newAPValue<=100)newAPValue*=100f;
//                 logger("float newAPValue="+newAPValue.ToString());
//                 return true;
//             }
//         }
    }
}
